using System;
using System.Text;
using UnityEditor.MemoryProfiler;

namespace PerfAssist.MemoryProfilerAdvanced.Editor
{
    internal class PrimitiveValueReader
    {
        private readonly MemorySection[] _heapSections;
        private readonly VirtualMachineInformation _virtualMachineInformation;

        public PrimitiveValueReader(VirtualMachineInformation virtualMachineInformation, MemorySection[] heapSections)
        {
            _virtualMachineInformation = virtualMachineInformation;
            _heapSections = heapSections;
        }

        public int ReadInt32(BytesAndOffset bo)
        {
            return BitConverter.ToInt32(bo.bytes, bo.offset);
        }

        public uint ReadUInt32(BytesAndOffset bo)
        {
            return BitConverter.ToUInt32(bo.bytes, bo.offset);
        }

        public long ReadInt64(BytesAndOffset bo)
        {
            return BitConverter.ToInt64(bo.bytes, bo.offset);
        }

        public ulong ReadUInt64(BytesAndOffset bo)
        {
            return BitConverter.ToUInt64(bo.bytes, bo.offset);
        }

        public short ReadInt16(BytesAndOffset bo)
        {
            return BitConverter.ToInt16(bo.bytes, bo.offset);
        }

        public ushort ReadUInt16(BytesAndOffset bo)
        {
            return BitConverter.ToUInt16(bo.bytes, bo.offset);
        }

        public byte ReadByte(BytesAndOffset bo)
        {
            return bo.bytes[bo.offset];
        }

        public sbyte ReadSByte(BytesAndOffset bo)
        {
            return (sbyte) bo.bytes[bo.offset];
        }

        public bool ReadBool(BytesAndOffset bo)
        {
            return ReadByte(bo) != 0;
        }

        public ulong ReadPointer(BytesAndOffset bo)
        {
            if (_virtualMachineInformation.pointerSize == 4)
                return ReadUInt32(bo);
            return ReadUInt64(bo);
        }

        public ulong ReadPointer(ulong address)
        {
            return ReadPointer(_heapSections.Find(address, _virtualMachineInformation));
        }

        public char ReadChar(BytesAndOffset bytesAndOffset)
        {
            return Encoding.Unicode.GetChars(bytesAndOffset.bytes, bytesAndOffset.offset, 2)[0];
        }

        public float ReadSingle(BytesAndOffset bytesAndOffset)
        {
            return BitConverter.ToSingle(bytesAndOffset.bytes, bytesAndOffset.offset);
        }

        public double ReadDouble(BytesAndOffset bytesAndOffset)
        {
            return BitConverter.ToDouble(bytesAndOffset.bytes, bytesAndOffset.offset);
        }
    }
}